package client;

import java.util.*;
import common.*;
import common.CMessage.*;

public class CClient extends Thread{
	private String 	s_name;			public String 	GetName(){return s_name;}
	private String	s_serverip; 	public String 	GetServerip(){return s_serverip;}
	private int		i_serverport;	public int 		GetServerport(){return i_serverport;}						
	private CConnectionThread o_connectthread;

	
	private CProcessMsgThread t_processmsg;
	public  Queue <CMessage> q_msg_out;
	public	Queue <CMessage> q_msg_in;
	public int i_outmsg_cnt;
	public int i_inmsg_cnt;
	//public Object syncobject;
	public CClientData o_clientdata;

	private void constructor(String name, String serverip, int port){
		s_name 		= name;
		s_serverip = serverip;
		i_serverport = port;
		

		i_outmsg_cnt = 0;
		i_inmsg_cnt = 0;

		q_msg_in 	= new LinkedList<CMessage>();
		q_msg_out 	= new LinkedList<CMessage>();		
		o_connectthread = new CConnectionThread(this);

		//syncobject = new Object();
	}
	
	public CClient(String name, String serverip, int port, int totplayer, boolean isChild){
		constructor(name, serverip, port);
		if(!isChild)
			o_clientdata = new CClientData(totplayer);
	}
	
	
	public void abort(){
		if(o_connectthread!=null)
			o_connectthread.abort();
		if(t_processmsg!=null)
			t_processmsg.abort();
		System.out.println("CClient::abort()");
	}
	public void Init() throws InterruptedException{
		System.out.println("CClient::Init()");
		o_connectthread.start();
		if(o_clientdata.GetClientId() == -1){
			o_clientdata.await();
			System.out.println("CClient::Init():Client Id Received " + o_clientdata.GetClientId());
		}
		t_processmsg = new CProcessMsgThread(this);
		System.out.println("CClient::Init():Starting processmsg thread");
		try{
			t_processmsg.start();
		}
		catch(Exception e){
			System.err.println("Exception caught");
			e.printStackTrace();
		}
		System.out.println("CClient::Init():processmsg thread started");
	}
	private void ProcessNextMessage(){
		//System.out.println("CClient:ProcessNextMessage");
		synchronized(q_msg_in){
			try {
				q_msg_in.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if(!q_msg_in.isEmpty()){
				CMessage msg = q_msg_in.poll();
				ProcessMessage(msg);
			}
		}
	}
	
	protected void ProcessMessage(Object obj){
			CMessage msg = (CMessage)obj;
			System.out.println("CClient:ProcessMessage. MsgId " + msg.l_msgid);	
			if(msg.e_type!=MsgType.SERVMSG){
				System.err.println("Not valid Message Type ");
				return;
			}
			if(msg.e_datatype == DataType.CONNECTED_CLIENT_INFO)
				o_clientdata.UpdateClientInfo(msg);
			if(msg.e_datatype == DataType.MSG_CHAT)
				o_clientdata.UpdateChatMsg(msg);
		}
	
	public void SendChatMsg(String sMsg){
		CMessage msg = CMessage.CreateMsg_Chat_Client(o_clientdata.GetClientId(),this.i_outmsg_cnt++,sMsg);
		q_msg_out.add(msg);
		return;
	}
	
	protected class CProcessMsgThread extends Thread{
		private CClient o_client;
		private boolean running;
		public CProcessMsgThread( CClient o_client){
			System.out.println("CClient::CProcessMsgThread::CProcessMsgThread()");
			this.o_client = o_client;
			running = false;
		}
		public void abort(){
			running = false;
			synchronized(o_client.q_msg_in){
				o_client.q_msg_in.notify();
			}
			System.out.println("CClient::CProcessMsgThread::abort()");
		}
		public void run(){
			System.out.println("CClient::CProcessMsgThread::Run()");
			running = true;
			while(running){
				if(o_client.o_clientdata.GetClientId()==-1){
					running =false;
					continue;
				}
				o_client.ProcessNextMessage();
			}
			System.out.println("CClient::CProcessMsgThread::Run() Finished Abort Done");	
		}
	}
	
	public void run(){
		try {
			Init();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
